/*************************************************************************
 *************************************************************************
 	 	 	 	 	 	 	M2SMA : Engine.h
 *************************************************************************
 *
 	 Copyright (C) 2008
 	 Steven Costiou, Julien Yven; Master 2 Complex Systems
 	 University of Western Brittany (UBO), Brest, France
 *
 *************************************************************************
 *************************************************************************
 *
 	 Copyright (C) 2011
 	 M2SMA reworked and simplified core, Steven Costiou, France
 *
 **************************************************************************
 **************************************************************************
 *
 	 The engine provides basically two things :

 	 - Handling of the whole multi-agent system
 	 - Interfaces to control the system from inside (agents) or from
 	   outside (users)

 	 It is the only object that can directly access to other agents and
 	 to the scheduler. Access to the system shall never be done directly
 	 through agents or the scheduler itself, but using the engine's
 	 public interfaces.

 	 Thus, any specific behavior shall be defined into inherited classes
 	 from the engine, and linked to an hypothetical inherited scheduler
 	 with new interfaces as well.

 	 The interfaces may be multiple for different purpose :

 	 - Access from outside the system
 	 - Access from inside the system, which can be divided in the following
 	  	  * Messages forwarding from agent(s) to agent(s)
 	  	  * Requests from an agent to an other specific agent's interface
 	  	  * Events from an agent to events-registered agent(s)

 *
 **************************************************************************
 **************************************************************************
 *
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/
 *
 **************************************************************************
 **************************************************************************/

#ifndef ENGINE_H
#define ENGINE_H

#include <string>
#include "Scheduler.h"
#include "PriorityScheduler.h"
#include "Agent.h"

#include "COMMON_LIBS.h"

using namespace std;

class Engine
{
    public:

        Engine();
        Engine(int aSchedulerType);
        ~Engine();

        /***************************************************************
         * SYSTEM PUBLIC INTERFACE
         ***************************************************************
         * The following methods form the public interface with the
         * multi-agents system.
         *
         * Any external or internal call to the system has to be done
         * throughout this interface.
         *
         * An external access is any call made by an object or a user
         * not part of the system, while an internal call is, basically,
         * a call made by an agent from inside the system.
         *
         * Inherited classes shall also define their own interface such
         * as this super engine's.
         ***************************************************************
         ***************************************************************/

        /**
         *	Adds a new agent to the system.
         */
        void createAgent(Agent* anAgent);

        /**
         * Adds an new agent to the system, at the given priority.
         * Works only with a priority scheduler.
         */
        void createAgentWithPriority(Agent* anAgent, short int aPriority);

        /**
         *	Remove an agent from the system.
         */
        void removeAgent(Agent* anAgent);

        /**
         *	Gets back the agent identified by its name, if it does exist.
         */
        Agent* getAgent(string aName);

        /**
         *	Gets back every agent of a given class, if they do exist.
         */
        set<Agent*>* getAllAgentOfClass(string aClassName);

        /**
         *	Gets back every existing agent.
         */
        vector<Agent*>* getAllAgents();

        /**
         *	Returns whether or not an agent identified by its name is kind of a given class,
         *	identified by its class name.
         */
        bool isKindOf(string aName, string aClassName);

        /**
         *	Returns whether or not an agent identified by a pointer is kind of a given class,
         *	identified by its class name.
         */
        bool ptrIsKindOf(Agent* anAgent, string aClassName);

        /**
         *	Checks if an agent identified by its name does exist.
         */
        bool agentDoesExist(string aName);

        /**
         *	Checks if a pointer on an agent does exist.
         */
        bool agentPointerDoesExist(Agent* anAgent);

        /**
         *	Performs a scheduling cycle.
         */
        void work();

        /**
         * 	Performs a given number of scheduling cycle.
         */
        void workForCycles(unsigned int numberOfCycles);

        void workUntilSystemBreakDown();

        void startSytem() { this->systemIsRunning = true; };

        void stopSystem() { this->systemIsRunning = false; };

    protected:

        void setScheduler(Scheduler* aScheduler) { this->scheduler = aScheduler; } ;
        Scheduler* getScheduler() { return this->scheduler; };

    private:

        void initializeAttributes();
        virtual void initializeScheduler();
        bool isClassNameInClassNamesVector(string aClassName, vector<string>* anAgentClassNames);

    private:

        Scheduler* scheduler;
        int schedulerType;
        bool systemIsRunning;
};

#endif /** ENGINE_H **/
